#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "basewindow.h"
#include <QInputDialog>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow)

{
    ui->setupUi(this);
}

MainWindow::MainWindow(QWidget *parent, QString newFilepath, QString gameFile) :
    QWidget(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setGeometry(this->x(),this->y(), 640, 640);
    this->setFocus();

    cheatMode = false;

    //Read in the player's name
    QString newUsername;
    if(gameFile == "new game")
    {
        bool ok;
        newUsername = QInputDialog::getText(this, "New Game" ,"Name:", QLineEdit::Normal, "", &ok);
        if ( !ok || newUsername.isEmpty())
                newUsername = "Anonymous";
    }
    this->setFocus();

    //Create the game map
    gameMap = new Map(this, 25, 25, newFilepath, newUsername);

    //Load Settings
    invertUpDown = dynamic_cast<BaseWindow*>(this->parent())->getInvertUpDown();

    //Set File Path
    this->filepath = newFilepath;

    //Load Font
    QFontDatabase::addApplicationFont(newFilepath + "Qubix.ttf");
    speedFont = new QFont("Qubix", 24, -1, false);
    ui->speedlbl->setFont(*speedFont);
    ui->paused->hide();
    ui->paused->setFont(*speedFont);
    ui->paused->setText("<font color='white'>Paused</font>");

    //Create Background Image
    QString space_background = newFilepath + "Images/bg.png";
    bg = QImage(space_background);

    //Load Ship Images
    ship01 = QImage(newFilepath + "Images/0001.png");
    ship02 = QImage(newFilepath + "Images/0002.png");
    ship03 = QImage(newFilepath + "Images/0003.png");
    ship04 = QImage(newFilepath + "Images/0004.png");
    ship05 = QImage(newFilepath + "Images/0005.png");
    ship06 = QImage(newFilepath + "Images/0006.png");
    ship07 = QImage(newFilepath + "Images/0007.png");
    ship08 = QImage(newFilepath + "Images/0008.png");
    ship09 = QImage(newFilepath + "Images/0009.png");

    //Connect the timer to the paint method and start the timer.
    this->gameTimer = new QTimer(this);
    connect(gameTimer, SIGNAL(timeout()), this, SLOT(incCounter()));
    connect(gameTimer, SIGNAL(timeout()), this, SLOT(repaint()));
    connect(this, SIGNAL(shipCrashed()), this, SLOT(endGame()));
    connect(this, SIGNAL(timerStart()), gameTimer, SLOT(start()));

    if(gameFile == "new game")
    {
        //Start a new game
        dynamic_cast<BaseWindow*>(this->parent())->logEvent("New game."); //EVENT LOG
        gameMap->loadCubes();
        gameTimer->start(33);
    }
    else
    {
        //Load a saved game
        this->gameMap->loadMap();
        this->incCounter();
        this->repaint();
    }

}

MainWindow::~MainWindow()
{
    delete ui;
}

bool cubeLessThan(Cube* c1, Cube* c2) //used for sorting cubes
{
    return c1->camDistance < c2->camDistance;
}

//Update method that gets run at 30 f/s
void MainWindow::paintEvent(QPaintEvent *event)
{
    //Checks that paintEvent was called by the timer
    bool logicUpdate = false;
    gameMap->counter2++;
    if(gameMap->counter2 != gameMap->counter)
        gameMap->counter2--;
    else
        logicUpdate = true;

    //Increment by amount every frequency seconds
    if(logicUpdate == true)
    {
        int amount = 1;
        int frequency = 2;
        if(this->gameMap->counter % (frequency*15) == 0)
        {
            gameMap->speed += amount;
        }

        //Update label displaying speed
        ui->speedlbl->setText("<font color='white'>Speed: " + QString::number(gameMap->speed) + "</font>");
    }

    //Create the painter
    QPainter painter(this);
    QPen pen( Qt::white );
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(pen);

    //Draw a window-sized background image
    painter.setBrush(QBrush(Qt::white, Qt::SolidPattern));
    QRect imageRect(0,0,this->width(), this->height());
    painter.drawImage(imageRect, bg);
    //painter.drawImage(0,0,bg);

    //Move the camera/ship if the user is pressing arrow keys
    if(logicUpdate == true)
        gameMap->camUpdate();

    //Draw the tunnel
    painter.setBrush(QBrush(Qt::white, Qt::SolidPattern));
    double leftX = ((0 - gameMap->x) * (this->width() / 30.0)) / (.001) + (this->width() / 2.0);
    double rightX = ((50 - gameMap->x) * (this->width() / 30.0))/ (.001) + (this->width() / 2.0);
    double topY = ((0 - gameMap->y) * (this->height() / 30.0)) / (.001)+ (this->height() / 2.0);
    double bottomY = ((50 - gameMap->y) * (this->height() / 30.0))/ (.001) + (this->height() / 2.0);
    double centerX = this->width() / 2.0;
    double centerY = this->height() / 2.0;

    painter.drawLine(centerX, centerY, leftX, topY);
    painter.drawLine(centerX, centerY, leftX, bottomY);
    painter.drawLine(centerX, centerY, rightX, topY);
    painter.drawLine(centerX, centerY, rightX, bottomY);

    pen.setColor(Qt::black);
    QPen pen2(Qt::black);
    painter.setPen(pen2);

    //Get each cube in the gameMap...
    QList<Cube *> allCubes = gameMap->findChildren <Cube *>();

    //Sort them by their distance from the camera
    qSort(allCubes.begin(), allCubes.end(), cubeLessThan);

    for (int i = allCubes.size() - 1; i >= 0; --i)
    {
        if(logicUpdate == true)
        {
            //Z-update (Move the cube forward)
            allCubes[i]->zUpdate();

            //Check for collision
            if(allCubes[i]->crashTest() && cheatMode == false)
            {
                dynamic_cast<BaseWindow*>(this->parent())->logEvent("Player crashed."); //EVENT LOG
                emit shipCrashed();
            }

            //Delete it?
            if(allCubes[i]->z < -10)
            {
                allCubes[i]->deleteLater();
                continue;
            }

            //Visibility update (Check if the cube should be displayed)
            allCubes[i]->visUpdate();            

            //camDistance update (Distance of the cube from the camera
            double temp = sqrt(((double)allCubes[i]->x - gameMap->x) *
                               (allCubes[i]->x - gameMap->x) +
                               (allCubes[i]->y - gameMap->y) *
                               (allCubes[i]->y - gameMap->y));
            allCubes[i]->camDistance = sqrt(temp*temp + ((double)allCubes[i]->z * allCubes[i]->z));
            allCubes[i]->camDistance *= 10;
        }

        //If the cube is visible...
        if(allCubes[i]->visible == true)
        {
            //Select the corrent color
            if(allCubes[i]->color == 0)
                painter.setBrush(QBrush(Qt::gray, Qt::SolidPattern));
            if(allCubes[i]->color == 1)
                painter.setBrush(QBrush(Qt::red, Qt::SolidPattern));
            if(allCubes[i]->color == 2)
                painter.setBrush(QBrush(Qt::green, Qt::SolidPattern));

            //Distance fade
            if(allCubes[i]->z > 400)
                painter.setOpacity(-(allCubes[i]->z /  400.0) + 2);
            else
                painter.setOpacity(1);

            //Draw the three polygons
            QPolygon p1;

            //Select the order to draw the sides
            int *orderTest = allCubes[i]->makePolygon(2);
            if((orderTest[6] > orderTest[0]) && (orderTest[4] < orderTest[2]))
            {
                //Draw the side
                p1.setPoints(4, allCubes[i]->makePolygon(1));
                painter.setBrush(QBrush(Qt::green, Qt::SolidPattern));
                painter.drawPolygon(p1);
                //Draw the bottom/top
                p1.setPoints(4, allCubes[i]->makePolygon(2));
                painter.setBrush(QBrush(Qt::blue, Qt::SolidPattern));
                painter.drawPolygon(p1);
            }
            else
            {
                //Draw the bottom/top
                p1.setPoints(4, allCubes[i]->makePolygon(2));
                painter.setBrush(QBrush(Qt::blue, Qt::SolidPattern));
                painter.drawPolygon(p1);
                //Draw the side
                p1.setPoints(4, allCubes[i]->makePolygon(1));
                painter.setBrush(QBrush(Qt::green, Qt::SolidPattern));
                painter.drawPolygon(p1);
            }

            //Draw the front
            p1.setPoints(4, allCubes[i]->makePolygon(0));
            painter.setBrush(QBrush(Qt::red, Qt::SolidPattern));
            painter.drawPolygon(p1);
        }
    }
    //Display collision cube

//    Cube collisionDisplay(gameMap, gameMap->x, gameMap->y + gameMap->shipOffset, 0, gameMap->shipWidth, 0);
//    QPolygon p2;
//    p2.setPoints(4, collisionDisplay.makePolygon(0));
//    painter.setBrush(QBrush(Qt::green, Qt::SolidPattern));
//    painter.drawPolygon(p2);

    //Draw the ship
    painter.setOpacity(1);
    double imageWidth = 250;
    painter.drawImage(((this->width() / 2) - (imageWidth / 2)),
                      ((this->height() / 2) + 100 - (imageWidth / 2)),
                      shipFile());

    painter.end();
}

//Handles key presses
void MainWindow::keyPressEvent(QKeyEvent *event)
{
    if(event->type() == QEvent::KeyPress)
    {
        //Arrow keys - move the ship
        if(event->key() == Qt::Key_Left)
            gameMap->left = true;
        if(event->key() == Qt::Key_Right)
            gameMap->right = true;
        if(invertUpDown) //uses up/down setting to choose behavior
        {
            if(event->key() == Qt::Key_Up)
                gameMap->down = true;
            if(event->key() == Qt::Key_Down)
                gameMap->up = true;
        } else {
            if(event->key() == Qt::Key_Up)
                gameMap->up = true;
            if(event->key() == Qt::Key_Down)
                gameMap->down = true;
        }

//        //Accelerate and decelerate
//        if(event->key() == Qt::Key_Z)
//            gameMap->speed -= 2;
//        if(event->key() == Qt::Key_X)
//            gameMap->speed += 2;

        //Cheat mode
        if(event->key() == Qt::Key_R)
            emit timerStart();

        //Pausing the game
        if(event->key() == Qt::Key_P)
        {
            if(this->gameTimer->isActive())
            {
                this->gameTimer->stop();
                ui->paused->show();
                dynamic_cast<BaseWindow*>(this->parent())->logEvent("Paused game."); //EVENT LOG
            }
            else
            {
                this->gameTimer->start(33);
                ui->paused->hide();
                dynamic_cast<BaseWindow*>(this->parent())->logEvent("Resumed game."); //EVENT LOG
            }
        }

        //Save the game
        if(event->key() == Qt::Key_S)
        {
            this->gameTimer->stop();
            ui->paused->show();
            this->gameMap->saveMap();
        }
        //Load the game
//        if(event->key() == Qt::Key_L)
//        {
//            this->gameTimer->stop();
//            this->gameMap->loadMap();
//            this->paintEvent(NULL);
//        }

        //Cheat mode!
        if(event->key() == Qt::Key_Control)
        {
            this->cheatMode = true;
        }
    }
}

//Handles key releases
void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
    if(event->type() == QEvent::KeyRelease)
    {
        //Arrow keys - move the ship
        if(event->key() == Qt::Key_Left)
            gameMap->left = false;
        if(event->key() == Qt::Key_Right)
            gameMap->right = false;
        if(invertUpDown)
        {
            if(event->key() == Qt::Key_Up)
                gameMap->down = false;
            if(event->key() == Qt::Key_Down)
                gameMap->up = false;
        } else {
            if(event->key() == Qt::Key_Up)
                gameMap->up = false;
            if(event->key() == Qt::Key_Down)
                gameMap->down = false;
        }

        //Accelerate and decelerate
//        if(event->key() == Qt::Key_Z)
//            gameMap->decelerate = false;
//        if(event->key() == Qt::Key_X)
//            gameMap->accelerate = false;

        //Cheat mode
        if(event->key() == Qt::Key_Control)
        {
            cheatMode = false;
        }
    }
}

QImage MainWindow::shipFile()
{
    if(gameMap->up == true)
    {
        if(gameMap->left == true)
            return ship01;
        else if(gameMap->right == true)
            return ship03;
        else
            return ship02;
    }
    else if(gameMap->down == true)
    {
        if(gameMap->left == true)
            return ship07;
        else if(gameMap->right == true)
            return ship09;
        else
            return ship08;
    }
    else
    {
        if(gameMap->left == true)
            return ship04;
        else if(gameMap->right == true)
            return ship06;
        else
            return ship05;
    }
}

void MainWindow::incCounter()
{
    this->gameMap->counter++;
}

void MainWindow::endGame()
{
    //Stop the timer and store the speed.
    this->gameTimer->stop();
    this->gameTimer->deleteLater();
    int finalSpeed = this->gameMap->speed;

    dynamic_cast<BaseWindow*>(this->parent())->logEvent("Final score: " + QString::number(finalSpeed)); //EVENT LOG

    //Create variables
    QVector<int> scoreList;
    QVector <QString> nameList;
    QFile file(filepath + "/gameData/highscores.txt");
    QStringList cubes;
    QString username = this->gameMap->username;
    bool highScore = false;

    //Read in the old high score list
    if (file.open(QIODevice::ReadWrite | QIODevice::Text))
    {
        QTextStream stream(&file);
        for(int i = 0; i < 5; ++i)
        {
            QString nameString, numString;
            nameString = stream.readLine(0);
            numString = stream.readLine(0);
            int intTemp = numString.toInt();

            //qDebug() << "Name: " << nameString << " Score: " << intTemp;

            //Check for a new high score
            if(finalSpeed > intTemp)
            {
                nameList.push_back(username);
                scoreList.push_back(finalSpeed);
                finalSpeed = -10;  //why?
                dynamic_cast<BaseWindow*>(this->parent())->logEvent("High score!"); //EVENT LOG
                highScore = true;
            }

            nameList.push_back(nameString);
            scoreList.push_back(intTemp);

            file.remove();
            file.close();
        }
    }

    //Write out the new high score list
    if(file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            QTextStream stream(&file);

            for(int i = 0; i < 5; ++i)
            {
                stream << nameList[i] << endl << scoreList[i] << endl;
            }
            file.close();
        }

    dynamic_cast<BaseWindow*>(this->parent())->showGameOver(highScore ,gameMap->speed);
    this->deleteLater();
}
